home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Internet Tools 1993 July / Internet Tools.iso / RockRidge / mail / metamail / richmail / iso2022.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-12-22  |  10.1 KB  |  376 lines

  1. /*-------------------------------------------------------------------------
  2.  
  3.   iso2022.c - Code for the ISO-2022 specific parts of the richtext processor.
  4.  
  5.   Copyright (c) 1992 Rhys Weatherley
  6.  
  7.   Permission to use, copy, modify, and distribute this material
  8.   for any purpose and without fee is hereby granted, provided
  9.   that the above copyright notice and this permission notice
  10.   appear in all copies, and that the name of Rhys Weatherley not be
  11.   used in advertising or publicity pertaining to this
  12.   material without specific, prior written permission.
  13.   RHYS WEATHERLEY MAKES NO REPRESENTATIONS ABOUT THE ACCURACY OR
  14.   SUITABILITY OF THIS MATERIAL FOR ANY PURPOSE.  IT IS PROVIDED
  15.   "AS IS", WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES.
  16.  
  17.   Revision History:
  18.   ================
  19.  
  20.    Version  DD/MM/YY  By  Description
  21.    -------  --------  --  --------------------------------------
  22.      1.0    21/06/92  RW  Original Version of iso2022.c
  23.  
  24.   You may contact the author by:
  25.   =============================
  26.  
  27.    e-mail: rhys@cs.uq.oz.au
  28.      mail: Rhys Weatherley
  29.        5 Horizon Drive
  30.        Jamboree Heights
  31.        Queensland 4074
  32.        Australia
  33.  
  34.   Acknowledgements:
  35.   ================
  36.  
  37.   Many thanks to Yutaka Sato (ysato@etl.go.jp) for protyping ISO-2022
  38.   support in a previous version of richtext, on whose code this is based.
  39.  
  40. -------------------------------------------------------------------------*/
  41.  
  42. #include <stdio.h>
  43. #include <ctype.h>
  44. #include "richlex.h"
  45. #include "richset.h"
  46.  
  47. /*
  48.  * Global data for this module.
  49.  */
  50. static    int    SwToAscii;
  51. static    int    SwToOther;
  52. static    int    OutPrevChar;
  53. static    int    OutPrevPrevChar;
  54. static    int    OutCharLen;
  55. static    int    OutCharSet;
  56. static    int    OutAsciiMode;
  57.  
  58. #define    OUT_ASCII    0
  59. #define    OUT_JIS        1
  60. #define    OUT_KSC        2
  61.  
  62. #define    ESC        033
  63. #define    SO        016
  64. #define    SI        017
  65.  
  66. #define    ISO_GENERIC_PREFIX    "x-iso-2022-gen-"
  67. #define    ISO_GENERIC_LEN        15
  68. #define    ISO_SHIFT_PREFIX    "x-iso-shift-"
  69. #define    ISO_SHIFT_LEN        12
  70. #define    ISO_CHARSET_PREFIX    "x-iso-charset-"
  71. #define    ISO_CHARSET_LEN        14
  72.  
  73. /*
  74.  * Initialise the ISO-2022 character set processor.
  75.  */
  76. iso2022_init (name)
  77. char    *name;
  78. {
  79.     SwToAscii = 'B';
  80.     SwToOther = 'B';
  81.     OutPrevChar = 0;
  82.     OutPrevPrevChar = 0;
  83.     OutCharLen = 1;
  84.     OutCharSet = OUT_ASCII;
  85.     OutAsciiMode = RICH_ENC_US_ASCII;
  86.     if (!name)
  87.     return;
  88.     if (!strncmp (name,"iso-2022-jp",11))
  89.     richtextencoding (RICH_ENC_JP_ASCII);
  90.     else if (!strncmp (name,"iso-2022-kr",11)) {
  91.     richtextencoding (RICH_ENC_KR_ASCII);
  92.     controloutput("\033$)C",0);
  93.     } else
  94.     richtextencoding (RICH_ENC_US_ASCII);
  95. }
  96.  
  97. /*
  98.  * Process a command for the ISO-2022 processor.
  99.  */
  100. int    iso2022_command (token,negated)
  101. char    *token;
  102. int    negated;
  103. {
  104.     int swchar;
  105.     if (!strcmp(token,"iso-2022-jp")) {
  106.         if (negated) {
  107.         /* Return to previous output mode */
  108.         controloutput("\033(B",0);
  109.         SwToAscii = 'B';
  110.         charsetpop(&iso2022_charset);
  111.     } else {
  112.         /* Enter JIS-X0208-1983 output mode */
  113.         charsetpush(&iso2022_charset);
  114.         richtextencoding(RICH_ENC_US_ASCII);
  115.         controloutput("\033(B",0);
  116.         SwToOther = 'B';
  117.     }
  118.     return (1);
  119.     } else if (!strcmp(token,"iso-2022-kr")) {
  120.     if (negated) {
  121.         /* Return to previous output mode */
  122.         controloutput("\017",0);
  123.         charsetpop(&iso2022_charset);
  124.     } else {
  125.         /* Enter KSC-5601 output mode */
  126.         charsetpush(&iso2022_charset);
  127.         richtextencoding(RICH_ENC_KR_ASCII);
  128.         controloutput("\033$)C\017",0);
  129.     }
  130.     return (1);
  131.     } else if (!strncmp(token,"x-jis-x0201",11)) {
  132.         if (negated) {
  133.         /* Return to previous output mode */
  134.         controloutput("\033(B",0);
  135.         SwToAscii = 'B';
  136.         charsetpop(&iso2022_charset);
  137.     } else {
  138.         /* Enter JIS-X-0201-1976 output mode */
  139.         charsetpush(&iso2022_charset);
  140.         richtextencoding(RICH_ENC_JP_ASCII);
  141.         controloutput("\033(J",0);
  142.         SwToAscii = 'J';
  143.     }
  144.     return (1);
  145.     } else if (!strncmp(token,"x-jis-x0208",11)) {
  146.         if (negated) {
  147.         /* Return to previous output mode */
  148.         controloutput("\033(B",0);
  149.         SwToAscii = 'B';
  150.         charsetpop(&iso2022_charset);
  151.     } else {
  152.         /* Enter JIS-X0208-* output mode */
  153.         charsetpush(&iso2022_charset);
  154.         if (!strcmp (token + 11,"-1978"))
  155.         SwToOther = '@';
  156.         else
  157.         SwToOther = 'B';
  158.         richtextencoding((SwToOther == '@' ? RICH_ENC_JIS_1978 :
  159.                           RICH_ENC_JIS_1983));
  160.         controloutput("\033$",0);
  161.         controlputc(SwToOther);
  162.     }
  163.     return (1);
  164.     } else if (!strcmp(token,"x-ksc-5601")) {
  165.         if (negated) {
  166.         /* Return to previous output mode */
  167.         controloutput("\017",0);
  168.         charsetpop(&iso2022_charset);
  169.     } else {
  170.         /* Enter KSC-5601 output mode */
  171.         charsetpush(&iso2022_charset);
  172.         richtextencoding(RICH_ENC_KSC_5601);
  173.         controloutput("\033$)C\016",0);
  174.     }
  175.     return (1);
  176.     } else if (!strncmp (token,ISO_GENERIC_PREFIX,ISO_GENERIC_LEN)) {
  177.         /* Process an escape sequence for changing character sets */
  178.     sscanf(token + ISO_GENERIC_LEN,"%x",&swchar);
  179.     if (swchar <= ' ' || swchar >= 0x7F)
  180.         return (1);
  181.     if (negated) {
  182.         /* Return to previous output mode from multi-byte mode */
  183.         if (!charsettop(&iso2022_charset))
  184.           charsetpush(&iso2022_charset);
  185.         richtextencoding((swchar == 'J' ? RICH_ENC_JP_ASCII :
  186.                           RICH_ENC_US_ASCII));
  187.         controloutput("\033(",0);
  188.         controlputc(swchar);
  189.         SwToAscii = swchar;
  190.     } else {
  191.         /* Enter multi-byte (Japanese) mode */
  192.         if (!charsettop(&iso2022_charset))
  193.           charsetpush(&iso2022_charset);
  194.         richtextencoding((swchar == '@' ? RICH_ENC_JIS_1978 :
  195.                           RICH_ENC_JIS_1983));
  196.         controloutput("\033$",0);
  197.         controlputc(swchar);
  198.         SwToOther = swchar;
  199.     }
  200.     return (1);
  201.     } else if (!strncmp (token,ISO_SHIFT_PREFIX,ISO_SHIFT_LEN)) {
  202.         /* Process a character set shift sequence */
  203.     if (!strcmp(token + ISO_SHIFT_LEN,"out") &&
  204.             RichtextCharEncoding == RICH_ENC_KR_ASCII) {
  205.         /* Enter KSC-5601 2-byte mode */
  206.         if (!charsettop(&iso2022_charset))
  207.           charsetpush(&iso2022_charset);
  208.         richtextencoding(RICH_ENC_KSC_5601);
  209.         controloutput("\016",0);
  210.     } else if (!strcmp (token + ISO_SHIFT_LEN,"in") &&
  211.         RichtextCharEncoding == RICH_ENC_KSC_5601) {
  212.         /* Return to US-ASCII from KSC-5601 */
  213.         if (!charsettop(&iso2022_charset))
  214.           charsetpush(&iso2022_charset);
  215.         richtextencoding(RICH_ENC_KR_ASCII);
  216.         controloutput("\017",0);
  217.     }
  218.     return (1);
  219.     } else {
  220.         return (0);
  221.     }
  222. }
  223.  
  224. /*
  225.  * Check for singleton ISO-2022 tokens.
  226.  */
  227. int    iso2022_single (token)
  228. char    *token;
  229. {
  230.     return (!strncmp (token,ISO_GENERIC_PREFIX,ISO_GENERIC_LEN) ||
  231.         !strncmp (token,ISO_SHIFT_PREFIX,ISO_SHIFT_LEN) ||
  232.         !strncmp (token,ISO_CHARSET_PREFIX,ISO_CHARSET_LEN));
  233. }
  234.  
  235. /*
  236.  * Determine the width of a ISO-2022 character.
  237.  */
  238. int    iso2022_width (ch)
  239. RCHAR    ch;
  240. {
  241.     return (ch & 0xFF00 ? 2 : 1);
  242. }
  243.  
  244. /*
  245.  * Determine if the current character can be used as a folding point.
  246.  */
  247. int    iso2022_fold (ch)
  248. RCHAR    ch;
  249. {
  250.     if (ch < 0x7F && isspace (ch)) {
  251.         return (1);
  252.     } else {
  253.         return ((ch & 0xFF00) != 0);
  254.     }
  255. }
  256.  
  257. /*
  258.  * Render the given ISO-2022 character.
  259.  */
  260. iso2022_render (ch,param)
  261. RCHAR    ch;
  262. void    *param;
  263. {
  264.     if (ch & 0xFF00) {
  265.     if (OutCharLen < 2) {
  266.         /* Add extra escape sequences after stray ASCII characters */
  267.         /* This normally happens in excerpts and signatures, etc.  */
  268.         if (OutAsciiMode == RICH_ENC_JP_ASCII) {
  269.         (*RichtextPutc) (033,param);
  270.         (*RichtextPutc) ('$',param);
  271.         (*RichtextPutc) (SwToOther,param);
  272.         } else if (OutAsciiMode == RICH_ENC_KR_ASCII) {
  273.         (*RichtextPutc) (SO,param);
  274.         }
  275.     }
  276.         (*RichtextPutc) ((int)((ch & 0xFF00) >> 8),param);
  277.         (*RichtextPutc) ((int)(ch & 0xFF),param);
  278.     } else {
  279.     if (OutCharLen > 1 && ch >= 0x20) {
  280.         /* Add extra escape sequences before stray ASCII characters */
  281.         /* This normally happens in excerpts and signatures, etc.   */
  282.         if (OutAsciiMode == RICH_ENC_JP_ASCII) {
  283.         (*RichtextPutc) (033,param);
  284.         (*RichtextPutc) ('(',param);
  285.         (*RichtextPutc) (SwToAscii,param);
  286.         } else if (OutAsciiMode == RICH_ENC_KR_ASCII) {
  287.         (*RichtextPutc) (SI,param);
  288.         }
  289.     }
  290.     (*RichtextPutc) ((int)(ch & 0xFF),param);
  291.     }
  292. }
  293.  
  294. /*
  295.  * Enter or leave the ISO-2022 encoding.
  296.  */
  297. iso2022_encoding (newenc)
  298. int    newenc;
  299. {
  300.     switch (newenc) {
  301.     case RICH_ENC_US_ASCII: controloutput("\033(B",0); break;
  302.     case RICH_ENC_JP_ASCII: controloutput("\033(J",0); break;
  303.     case RICH_ENC_KR_ASCII: controloutput("\017",0);   break;
  304.     case RICH_ENC_JIS_1978: controloutput("\033$@",0); break;
  305.     case RICH_ENC_JIS_1983: controloutput("\033$B",0); break;
  306.     case RICH_ENC_KSC_5601: controloutput("\016",0);   break;
  307.     default:        controloutput("\033(B",0); break;
  308.     }
  309. }
  310.  
  311. /*
  312.  * Define the ISO-2022-JP and ISO-2022-KR character set processor.
  313.  */
  314. struct     charsetproc    iso2022_charset =
  315.       {"iso-2022-jp:iso-2022-kr",
  316.        iso2022_init,
  317.        iso2022_command,
  318.        iso2022_single,
  319.        iso2022_width,
  320.        iso2022_fold,
  321.        iso2022_render,
  322.        iso2022_encoding};
  323.  
  324. /*
  325.  * Define an output routine for slotting into RichtextPutc so
  326.  * that ISO-2022 escape sequences are treated correctly.
  327.  */
  328. int    iso2022_fputc (ch,file)
  329. int    ch;
  330. FILE    *file;
  331. {
  332.     if (OutPrevChar == ESC && ch == '(') {
  333.     /* Process escape sequences that end JIS 2-byte modes */
  334.     OutCharLen = 1;
  335.     OutCharSet = OUT_ASCII;
  336.     OutAsciiMode = RICH_ENC_JP_ASCII;
  337.     }
  338.     if (OutPrevPrevChar == ESC && OutPrevChar == '$') {
  339.     /* Process escape sequences that start JIS 2-byte modes */
  340.         if (ch != ')') {    /* ')' is for Korean, so ignore it */
  341.         OutCharLen = 2;
  342.         OutCharSet = OUT_JIS;
  343.         OutAsciiMode = RICH_ENC_JP_ASCII;
  344.     }
  345.     }
  346.     if (ch == SO) {
  347.     OutCharLen = 2;
  348.     OutCharSet = OUT_KSC;
  349.     OutAsciiMode = RICH_ENC_KR_ASCII;
  350.     } else if (ch == SI) {
  351.     OutCharLen = 1;
  352.     OutCharSet = OUT_ASCII;
  353.     OutAsciiMode = RICH_ENC_KR_ASCII;
  354.     }
  355.     if (ch == '\n' && OutCharLen == 2) {
  356.         /* Two-byte characters cannot cross line boundaries */
  357.     if (OutCharSet == OUT_JIS) {
  358.             fputc (ESC,file);
  359.             fputc ('(',file);
  360.             fputc (SwToAscii,file);
  361.             fputc ('\n',file);
  362.             fputc (ESC,file);
  363.             fputc ('$',file);
  364.             fputc (SwToOther,file);
  365.     } else if (OutCharSet == OUT_KSC) {
  366.         fputc (SI,file);
  367.         fputc ('\n',file);
  368.         fputc (SO,file);
  369.     }
  370.     } else {
  371.         fputc (ch,file);
  372.     }
  373.     OutPrevPrevChar = OutPrevChar;
  374.     OutPrevChar = ch;
  375. }
  376.